package com.felix.ocoupon.service.impl;

import com.felix.ocoupon.constant.Constant;
import com.felix.ocoupon.dao.IOcouponTemplateDao;
import com.felix.ocoupon.entity.OcouponTemplate;
import com.felix.ocoupon.service.IAsyncService;
import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author hsufelix
 * @email hsufelix@yeah.net
 * @Date 2020/11/14
 */
@Slf4j
@Service
public class AsyncService implements IAsyncService {
    @Autowired
    private IOcouponTemplateDao templateDao;
    @Autowired
    private StringRedisTemplate redisTemplate;

    public AsyncService(IOcouponTemplateDao templateDao,
                        StringRedisTemplate redisTemplate) {
        this.templateDao = templateDao;
        this.redisTemplate = redisTemplate;
    }

    /**
     * <h2>根据模板一步的创建优惠券码</h2>
     *
     * @param template 优惠券模板实体
     */
    @Async("getAsyncExecutor")
    @Override
    public void asyncCreateOcounponByTemplate(OcouponTemplate template) {
        Stopwatch watch = Stopwatch.createStarted();
        Set<String> couponCodes = buildCouponCode(template);
        String redisKey = String.format(
                "%s%s",
                Constant.RedisPrefix.COUPON_TEMPLATE,
                template.getId().toString()
        );
        log.info("Push CouponCode to Redis: {}",
                redisTemplate.opsForList().rightPushAll(redisKey, couponCodes));

        template.setAvailable(true);
        templateDao.save(template);
        watch.stop();

        log.info("Construct CouponCode By Template Cost: {}ms",
                watch.elapsed(TimeUnit.MILLISECONDS));

        log.info("CouponTemplate({}) Is Available!", template.getId());

        // TODO 可扩张邮件信息
    }

    private Set<String> buildCouponCode(OcouponTemplate template) {
        Stopwatch watch = Stopwatch.createStarted();

        Set<String> result = new HashSet<String>(template.getCounts());

        String prefix4 = template.getProductLine().getCode().toString()
                + template.getCategory().getCode();
        String date = new SimpleDateFormat("yyMMdd")
                .format(template.getCreateTime());

        for (int i = 0; i != template.getCounts(); ++i) {
            result.add(prefix4 + buildCouponCodeSuffix14(date));
        }

        while (result.size() < template.getCounts()) {
            result.add(prefix4 + buildCouponCodeSuffix14(date));
        }
        assert result.size() == template.getCounts();
        watch.stop();
        log.info("Build Coupon Code Cost: {}ms", watch.elapsed(TimeUnit.MILLISECONDS));
        return result;
    }

    private String buildCouponCodeSuffix14(String date){
        char[] bases = new char[]{'1', '2', '3', '4', '5', '6', '7', '8', '9'};

        List<Character> chars = date.chars()
                .mapToObj(e -> (char) e).collect(Collectors.toList());
        Collections.shuffle(chars);

        String mid6 = chars.stream()
                .map(Object::toString)
                .collect(Collectors.joining());

        String suffix8 = RandomStringUtils.random(1, bases)
                + RandomStringUtils.randomNumeric(7);

        return mid6 + suffix8;

    }
}
